﻿#region Using References

using System;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Beaker.Services.Tasks;
using Beaker.Services.Tasks.Synchronous;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace Beaker.Services.Specs
{
	[TestClass]
	public class SynchronousTaskServiceSpecs
	{
		[TestMethod]
		public void TaskShouldBeExecutedSynchronously()
		{
			// arrange
			bool hasRun = false;
			ITaskService taskService = new SynchronousTaskService();

			// act
			taskService.Execute( () => hasRun = true );

			// assert
			hasRun.Should().Be( true );
		}

		[TestMethod]
		public void ExceptionIsCatchedAndAvailableOnTask()
		{
			// arrange
			ITaskService taskService =  new SynchronousTaskService();

			// act
			Task task = taskService.Execute( () => { throw new Exception( "Foobar" ); } );
			
			// assert
			task.IsFaulted.Should().BeTrue();
			task.Exception.Should().NotBeNull();
		}

		[TestMethod]
		public void ExceptionIsCatchedAndRetrownOnAwaitEvenThoughItWasSynchrounous()
		{
			// arrange
			ITaskService taskService = new SynchronousTaskService();

			// act
			Task task = taskService.Execute( () => { throw new Exception( "Foobar" ); } );

			// assert
			Action wait = task.Wait;
			wait.ShouldThrow<Exception>();
		}

		[TestMethod]
		public void CollectionOfTaskReturnsAllResults()
		{
			// arrange
			ITaskService taskService = new SynchronousTaskService();
			ITaskCollection<int> collection = taskService.CreateCollection<int>();

			// act
			collection.Execute( () => 1 );
			collection.Execute( () => 3 );
			collection.Execute( () => 4 );
			collection.Execute( () => 2 );
			IObservable<int> observable = collection.ObserveResults();

			// assert
			int[] result = observable.ToArray().Wait();
			result.Should().Contain( new[] { 1, 2, 3, 4 } );
		}
	}
}
